#pragma once
#include <gtest/gtest.h>
#include <spatialindex/SpatialIndex.h>
#include <iostream>
#include <vector>

using namespace SpatialIndex;
using namespace std;

// 自定义数据类，用于存储与空间对象关联的 ID 或其他信息
class MyData : public IData {
 public:
  id_type m_id;

  MyData(id_type id) : m_id(id) {}

  // 必须实现的纯虚函数
  // IData* clone() { return new MyData(m_id); }

  uint32_t getByteArraySize() { return sizeof(id_type); }

  void loadByteArray(byte* data) { memcpy(data, &m_id, sizeof(id_type)); }

  void storeByteArray(byte* data) { memcpy(&m_id, data, sizeof(id_type)); }
};

// example of a Visitor pattern.
// findes the index and leaf IO for answering the query and prints
// the resulting data IDs to stdout.
class MyVisitor : public IVisitor {
 public:
  size_t m_indexIO{0};
  size_t m_leafIO{0};
  vector<id_type> ids;

 public:
  MyVisitor() = default;

  void visitNode(const INode& n) override {
    if (n.isLeaf())
      m_leafIO++;
    else
      m_indexIO++;
  }

  void visitData(const IData& d) override { ids.push_back(d.getIdentifier()); }

  void visitData(std::vector<const IData*>& v) override { cout << v[0]->getIdentifier() << " " << v[1]->getIdentifier() << endl; }
};

TEST(RTreeQueryTest, BasicAssertion) {

  // 1. 创建内存中的 R-tree
  // IStorageManager* disk = StorageManager::createNewMemoryStorageManager();
  // id_type indexIdentifier;
  // ISpatialIndex* tree = RTree::createNewRTree(*disk, 0.7, 100, 10, 2, SpatialIndex::RTree::RV_RSTAR, indexIdentifier);

  // 1. 创建磁盘的 R-tree
  std::string baseName = "rtree_test";
  IStorageManager* diskfile = StorageManager::createNewDiskStorageManager(baseName, 4096);
  StorageManager::IBuffer* file = StorageManager::createNewRandomEvictionsBuffer(*diskfile, 10, false);

  id_type indexIdentifier;
  ISpatialIndex* tree = RTree::createNewRTree(*file, 0.7, 100, 10, 2, SpatialIndex::RTree::RV_RSTAR, indexIdentifier);

  // 2. 插入一些矩形（每个矩形由 min 和 max 坐标定义）

  double p1[2], p2[2];
  p1[0] = p1[1] = 0.0;
  p2[0] = p2[1] = 2.0;
  Region r1(Point(p1, 2), Point(p2, 2));  // [0,2] x [0,2]
  p1[0] = p1[1] = 3.0;
  p2[0] = p2[1] = 5.0;
  Region r2(Point(p1, 2), Point(p2, 2));  // [0,2] x [0,2]
  p1[0] = p1[1] = 1.0;
  p2[0] = p2[1] = 4.0;
  Region r3(Point(p1, 2), Point(p2, 2));  // [0,2] x [0,2]
  // Region r3(Point(1.0, 1.0, 2), Point(4.0, 4.0, 2));  // [1,4] x [1,4]

  tree->insertData(0, nullptr, r1, 1);  // ID = 1
  tree->insertData(0, nullptr, r2, 2);  // ID = 2
  tree->insertData(0, nullptr, r3, 3);  // ID = 3

  // 如果需要关联自定义数据（如上面的 MyData），可以这样：
  // MyData d1(1);
  // tree->insertData(d1.getByteArraySize(), reinterpret_cast<const uint8_t*>(&d1.m_id), r1, 1);

  // 3. 范围查询：查找与 [1.5, 3.5] x [1.5, 3.5] 相交的对象
  p1[0] = 1.5;
  p1[1] = 1.5;
  p2[0] = 3.5;
  p2[1] = 3.5;
  Region queryRegion(Point(p1, 2), Point(p2, 2));

  // MyVisitor visitor;
  MyVisitor visitor;
  tree->intersectsWithQuery(queryRegion, visitor);

  cout << "Range query results (IDs): ";
  for (id_type id : visitor.ids) {
    cout << id << " ";
  }
  cout << endl;

  // 4. 最近邻查询：查找离点 (0.5, 0.5) 最近的 2 个对象
  p1[0] = 0.5;
  p1[1] = 0.5;
  Point queryPoint(p1, 2);
  vector<id_type> knnResults;
  tree->nearestNeighborQuery(2, queryPoint, visitor);
  // 注意：上面的 visitor 会被复用，但 nearestNeighborQuery 也会调用 visitData
  // 所以我们重新创建一个 visitor 更清晰：
  MyVisitor knnVisitor;
  tree->nearestNeighborQuery(2, queryPoint, knnVisitor);
  cout << "kNN query results (IDs): ";
  for (id_type id : knnVisitor.ids) {
    cout << id << " ";
  }
  cout << endl;

  // 5. 清理资源
  delete tree;
  // delete disk;
  delete file;
  delete diskfile;

  EXPECT_EQ(1, 1);
}
